<?php
class SysAuth {
    private function __construct() {}
    
    public static function getSysAcos($forceGet=false) {
        $sysAcos = Cache::eternal('Auth', 'SysAco');
        if (false == $sysAcos || $forceGet) {
            $sysAcos = array();
            $acoTable = Table::getTable('sys_aco');
            $acoList = $acoTable->findAll('1=1');
            foreach ($acoList as $aco) {
                $sysAcos[$aco['aco_id']] = $aco;
            }
            Cache::eternal('Auth', 'SysAco', $sysAcos);
        }
        return $sysAcos;
    }
    
    public static function getUserRoles($userId) {
        static $userRoles = array();
        $roleList = $userRoles[$userId];
        if (false == isset($userRoles[$userId])) {
            $mapping = Config::get('ROLE_MAPPING');
            $mapTable = Table::getTable($mapping['table']);
            $findCond[$mapping['user_id']] = $userId;
            $roleColumnName = $mapping['role_id'];
            $roleList = $mapTable->findAll($findCond, $roleColumnName . ' as role_id', $roleColumnName);
            $roles = array();
            foreach ($roleList as $row) {
                $roles[] = $row['role_id'];
            }
            $userRoles[$userId] = $roles;
        }
        return $userRoles[$userId];
    }
    
    public static function getAcosByRoles($roles, $aclGroup = 1) {
        if (false == is_array($roles)) $roles = array();
        $roleIds = "'" . implode("','", $roles) . "'";
        $aclTable = Table::getTable('sys_acl');
        $acoList = $aclTable->findAll('acl_group=' . $aclGroup . ' AND aro_id IN (' . $roleIds . ')');
        $acoArray = array('');
        foreach ($acoList as $aco) {
            $acoArray[$aco['aco_id']] = $aco;
        }
        return $acoArray;
    }
    
    public static  function saveAro($aroData) {
        
    }
    
    public static  function saveAcl($aclData) {
        
    }
    
    public static function checkAuth($authName, $isSuper) {
        $sysAcos = self::getSysAcos();
        $acoId = strtoupper(MODULE_NAME . '_' . ACTION_NAME);
        $acoTable = Table::getTable('sys_aco');
        $cond = array('aco_id'=>$acoId);
        if (false == isset($sysAcos[$acoId])) {
            $acoData = array('aco_id'   =>$acoId,
                             'aco_module'=>MODULE_NAME,
                             'aco_action'=>ACTION_NAME,
                             'aco_caption'=>$authName);
            if(false == $acoTable->find($cond)) {
                $acoTable->save($acoData);
            } else {
                $acoTable->save($acoData, $cond);
            }
            Cache::delEternal('Auth', 'SysAco');
        }
        
        if (false == Config::get('USE_SYS_AUTH') || true == $isSuper) {
            return true;
        } else {
            $userSessKey = Config::get('AUTH_SESSION_KEY');
            $userId = Session::get($userSessKey);
            $roles = self::getUserRoles($userId);
            $aclCount = 0;
            if(sizeof($roles) > 0) {
                $roleList = "'" . implode("','", $roles) . "'";
                $aclTable = Table::getTable('sys_acl');
                $aclCount = $aclTable->count('aco_id = ' . quote($acoId) . ' AND aro_id IN (' . $roleList . ')');
            }
            return $aclCount;
        }
    }
    
    public static function delete($acoId) {
        
    }
    
    public static function renew($moduleName='') {
        $moduleName = ucfirst($moduleName);
        if($moduleName) {
            $authActions = array($moduleName=>self::scanModule($moduleName));
        } else {
            $authActions = self::scanAuths();
        }
        $acoTable = Table::getTable('sys_aco');
        $delCond = '1=1';
        if($moduleName) $delCond = array('aco_module'=>$moduleName);
        $acoTable->delete($delCond);
        foreach($authActions as $moduleName=>$actions) {
            foreach($actions as $action=>$authCaption) {
                $acoData = array('aco_id'=>strtoupper($moduleName . '_' . $action),
                                 'aco_module'=>$moduleName,
                                 'aco_action'=>$action,
                                 'aco_caption'=>$authCaption);
                $acoTable->save($acoData);
            }
        }
        self::getSysAcos(true);
    }

    private static function scanAuths() {
        $actionFiles = glob(ACTION_DIR . '/*Action.class.php');
        $authActions = array();
        foreach($actionFiles as $actionFile) {
            $fileName = str_replace(ACTION_DIR . '/', '', $actionFile);
            $moduleName = str_replace('Action.class.php', '', $fileName);
            $actions = self::scanModule($moduleName);
            if($actions) $authActions[ucfirst($moduleName)] = $actions;
        }

        return $authActions;
    }   

    private static function scanModule($moduleName) {
        $moduleFile = ACTION_DIR . '/' . $moduleName . 'Action.class.php';
        $tokens = token_get_all(file_get_contents($moduleFile));
        $funcIndex = array();
        for ($i=0,$j=sizeof($tokens);$i<$j;$i++ ) {
            if(is_array($tokens[$i]) && T_FUNCTION == $tokens[$i][0]) {
                $funcIndex[] = $i;
            }
        }
        $maxIndex = $i;
        $authActions = array();
        for ($i=0, $j=sizeof($funcIndex);$i<$j;$i++) {
            $methodName = '';
            $isAuthAction = false;
            $nextIndex = $i + 1 == $j ? $maxIndex : $funcIndex[$i+1];
            for ($m=$funcIndex[$i];$m<$nextIndex;$m++) {
                if(is_array($tokens[$m])) {
                    if (T_STRING == $tokens[$m][0] && '' == $methodName) {
                        $methodName = $tokens[$m][1];
                    }
                    if ('' != $methodName && T_STRING == $tokens[$m][0] && 'isAuthAction' == $tokens[$m][1]) {
                        $isAuthAction = true;
                    }
                    if ($isAuthAction && T_CONSTANT_ENCAPSED_STRING == $tokens[$m][0]) {
                        $actionName = preg_replace('/' . Config::get('ACTION_SUFFIX') . '$/', '', preg_replace('/^' . Config::get('ACTION_PREFIX') . '/', '', $methodName));
                        $actionName = strtolower($actionName[0]) . substr($actionName, 1);
                        $authActions[$actionName] = trim($tokens[$m][1], "\"'");
                        break;
                    }
                }
            }
        }
        return $authActions;
    }
};
?>